<?php

class HttpServer
{

    private $client;

    const PORT = 81;

    public function __construct()
    {
        $this->client = new Swoole\Http\Server('127.0.0.1', self::PORT, SWOOLE_BASE);

        $this->client->set(
            [
                'worker_num' => 1, //指定启动的worker进程数, 设置为CPU的1-4倍最合理
                'task_worker_num' => 1, //服务器开启的task进程数
            ]
        );

        $this->client->on("start", [$this, 'onStart']);
        $this->client->on("workerStart", [$this, 'onWorkerStart']);
        $this->client->on("request", [$this, 'onRequest']);
        $this->client->on("task", [$this, 'onTask']);
        $this->client->on("finish", [$this, 'onFinish']);

        $this->client->start();
    }

    /**
     * @param $server
     */
    public function onStart($server)
    {
        echo "Swoole http server is started at http://127.0.0.1:" . self::PORT . "\n";
    }

    public function onWorkerStart($server, $worker_id)
    {
        // 定义应用目录
        define('DS', DIRECTORY_SEPARATOR);
        define('ROOT', realpath('../') . DS);
        echo 'ROOT: ' . ROOT . PHP_EOL;
        echo '__DIR__: ' . __DIR__ . PHP_EOL;
        define('APP', ROOT . 'app');
        define('APP_MODULE', 'app');
        define('CORE', ROOT . 'core');

        // 引入自动加载
        echo ROOT . 'vendor/autoload.php';
        require ROOT . 'vendor/autoload.php';

        // 自定义加载器
        require_once CORE . '/Base.php';

        spl_autoload_register('\core\Base::load');
        \core\Base::run();
    }

    /**
     * request回调
     * @param $request
     * @param $response
     */
    public function onRequest($request, $response)
    {
        //$response->header('Content-Type', 'text.txt/plain');
        //$response->end('Hello World');
        //$file = $request->files['files'];

        //$response->end(file_get_contents("../app/views/ws.html"));
        //$response->end(file_get_contents("../app/views/upload-ws.html"));

        // 创建一个 Mysql 的协程客户端
        $mysql = new Swoole\Coroutine\MySQL();
        // 调用 mysql->connect 时发生 IO 操作，底层会调用 C 函数 coro_save 保存当前协程的状态，
        // 包括 Zend VM 上下文以及协程描述的信息，并调用 coro_yield 让出程序控制权，当前的请求会挂起。
        // 当协程让出控制权之后，会继续进入 EventLoop 处理其他事件，这时 Swoole 会继续去处理其他客户端发来的 Request。
        $res = $mysql->connect([
            'host' => '103.23.46.74',
            'user' => 'group_four',
            'password' => 'qdDFgzUfTo7OQaAv',
            'database' => 'hyper'
        ]);

        // IO 事件完成后，MySQL 连接成功或失败，底层调用 C 函数 coro_resume 恢复对应的协程，恢复 ZendVM 上下文，继续向下执行 PHP 代码。
        if ($res == false) {
            $response->end("MySQL connect fail");
            return;
        }

        // mysql->query 的执行过程和 mysql->connect 一致，也会进行一次协程切换调度
        $ret = $mysql->query('show tables', 2);

        // 所有操作完成后，调用 end 方法返回结果，并销毁此协程。
        //$response->end('swoole response is ok, result='.var_export($ret, true));

        /*如果swoole 没有提供协程客户端，那么可以通过 $server->taskCo() 把对 mongodb 的操作，投递到异步 task 中。
        投递到异步 task 后，将发生协程切换，可以继续处理其他的请求，提供并发能力。*/
        $tasks = [
            ['method' => 'mail', 'data' => "hello mysql"],
            ['method' => 'mongoDb', 'data' => "hello mongo"],
        ];
        //$result = $this->client->taskCo($tasks, 0.5);
        $result = $this->client->task(['method' => 'mongoDb', 'data' => "hello mongo"]);
        $response->end('Test End, Result: ' . var_export($result, true));
    }

    public function onTask($server, $taskId, $workerId, $data)
    {
        // 分发 task 任务机制，让不同的任务 走不同的逻辑
        $obj = new app\common\business\SwooleTask;

        $param = is_string($data) ? json_decode($data, true) : $data;
        $method = $param['method'];
        return $obj->$method($param['data']);
    }

    public function onFinish($server, $taskId, $data)
    {
        echo "Swoole http server is finished\n";
    }
}

new HttpServer();